GLOBAL ssf_hand
GLOBAL snp_hand
GLOBAL gpf_hand
GLOBAL pf_hand

GLOBAL hacersnp
GLOBAL hacergpf
GLOBAL hacerssf

GLOBAL _int8

GLOBAL  _read_msw,_lidt
GLOBAL  _int_80_hand
GLOBAL  _int_09_hand
GLOBAL  _int_08_hand
GLOBAL  write, read, getVal, setVal
GLOBAL  ioIn, ioOut
GLOBAL  restart
GLOBAL  _Lights
GLOBAL  _mascaraPIC1,_mascaraPIC2,_Cli,_Sti
GLOBAL  _debug
GLOBAL _int8
GLOBAL _GetESP

EXTERN  int_09
EXTERN  __write
EXTERN  __read
EXTERN  __getVal
EXTERN  __setVal
EXTERN  inportb
EXTERN  outportb


EXTERN gpf
EXTERN ssf
EXTERN snp
EXTERN pf

EXTERN LoadESP
EXTERN SaveESP
EXTERN SaveOrigESP
EXTERN GetTemporaryESP
EXTERN GetNextProcess

SECTION .text

_GetESP:
    mov eax, esp
    ret

_int8:
    cli
    int 08h
    sti
    ret

gpf_hand:              ; Handler de excepción "General protection exception"
    push ds
    push es             ; Se salvan los registros
    pusha               ; Carga de DS y ES con el valor del selector
    pushf
    mov eax, 666666h
    mov ax, 10h         ; a utilizar.
    mov ds, ax
    mov es, ax
    call gpf
    mov al,20h          ; Envio de EOI generico al PIC
    out 20h,al
    popf
    popa
    pop ax
    pop ax
    jmp $
    iret

ssf_hand:              ; Handler de excepción "Stack exception"
    push ds
    push es             ; Se salvan los registros
    pusha               ; Carga de DS y ES con el valor del selector
    pushf
    mov ax, 10h         ; a utilizar.
    mov ds, ax
    mov es, ax
    call ssf
    mov al,20h          ; Envio de EOI generico al PIC
    out 20h,al
    popf
    popa
    pop ax
    pop ax
    jmp $
    iret

snp_hand:              ; Handler de excepción "Segment not present"
    push ds
    push es             ; Se salvan los registros
    pusha               ; Carga de DS y ES con el valor del selector
    pushf
    mov ax, 10h         ; a utilizar.
    mov ds, ax
    mov es, ax
    call snp
    mov al,20h          ; Envio de EOI generico al PIC
    out 20h,al
    popf
    popa
    pop ax
    pop ax
    jmp $
    iret

pf_hand:             ; Handler de excepxión "Divide by zero"
    push ds
    push es             ; Se salvan los registros
    pusha               ; Carga de DS y ES con el valor del selector
    pushf
    mov ax, 10h         ; a utilizar.
    mov ds, ax
    mov es, ax
    call pf
    mov al,20h          ; Envio de EOI generico al PIC
    out 20h,al
    popf
    popa
    pop es
    pop ds
    jmp $
    iret


[global _read_cr0]
_read_cr0:
	mov eax, cr0
	retn

[global _write_cr0]
_write_cr0:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr0,  eax
	pop ebp
	retn

[global _read_cr3]
_read_cr3:
	mov eax, cr3
	retn

[global _write_cr3]
_write_cr3:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr3, eax
	pop ebp
	retn

_Cli:
    cli ;limpia flag de interrupciones
    ret

_Sti:

    sti ; habilita interrupciones por flag
    ret

_mascaraPIC1: ; Escribe mascara del PIC 1
    push ebp
    mov ebp, esp
    mov ax, [ss:ebp+8] ; ax = mascara de 16 bits
    out 21h, al
    pop ebp
    retn

_mascaraPIC2: ; Escribe mascara del PIC 2
    push ebp
    mov ebp, esp
    mov ax, [ss:ebp+8] ; ax = mascara de 16 bits
    out 0A1h, al
    pop ebp
    retn

_read_msw:
    smsw ax ; Obtiene la Machine Status Word
    retn


_lidt: ; Carga el IDTR
    push ebp
    mov ebp, esp
    push ebx
    mov ebx, [ss: ebp + 6] ; ds:bx = puntero a IDTR
    rol ebx,16
    lidt [ds: ebx] ; carga IDTR
    pop ebx
    pop ebp
    retn

_int_08_hand:           ; Handler de INT 8 ( Timer tick)
    cli
    pushad
    mov eax, esp
    push eax
    call SaveESP
    pop eax
    call GetTemporaryESP
    mov esp, eax
    call GetNextProcess
    push eax
    call LoadESP
    pop ebx
    mov esp,eax
    popad

    mov al,20h          ; Envio de EOI generico al PIC
    out 20h,al

    sti

    iret


_int_09_hand: ; Handler de INT 9 ( Keyboard )
    push ds
    push es ; Se salvan los registros
    pusha ; Carga de DS y ES con el valor del selector
    mov ax, 10h ; a utilizar.
    mov ds, ax
    mov es, ax
    call int_09
    mov al, 20h ; Envio de EOI generico al PIC
    out 20h, al
    popa
    pop es
    pop ds
    iret

_int_80_hand: ; Handler de INT 80 ( ReadWrite )
    push ds
    push es ; Se salvan los registros
    pusha   ; Carga de DS y ES con el valor del selector

    cmp eax, 0 ; caso write
    jz  _oWrite

    cmp eax, 1 ; caso read
    jz _oRead

    cmp eax, 2 ; caso I/O in operation
    jz _oIoIn

    cmp eax, 3 ; caso I/O out operation
    jz _oIoOut

    cmp eax, 10 ; caso getVal
    jz _oGetVal

    cmp eax, 11 ; caso getVal
    jz _oSetVal


_oEnd:
    mov al, 20h ; Envio de EOI generico al PIC
    out 20h, al
    popa
    pop es
    pop ds
    iret

_oWrite:            ;Parametros cargados por Write
    push edx        ;edx = size
    push ecx        ;ecx = buffer
    push ebx        ;ebx = file descriptor
    call __write    ;write @kernel.c

    pop edx
    pop ecx
    pop ebx
    jmp _oEnd       ; Se sacan los parametros de la pila y retorna

_oRead:
    push edx
    push ecx
    push ebx
    call __read     ;read @kernel.c

    pop edx
    pop ecx
    pop ebx
    jmp _oEnd

_oSetVal:
    push ecx        ;ecx = buffer
    push ebx        ;ebx = operacion de setVal
    call __setVal    ;setVal @kernel.c

    pop ecx
    pop ebx
    jmp _oEnd       ; Se sacan los parametros de la pila y retorna

_oGetVal:
    push ecx
    push ebx
    call __getVal     ;getVal @kernel.c

    pop ecx
    pop ebx
    jmp _oEnd

_oIoIn:
    push ecx
    push ebx
    call inportb

    pop  ebx
    pop  ecx
    jmp _oEnd

_oIoOut:
    push ebx
    push ecx
    call outportb
    pop  ebx
    pop  ecx
    jmp _oEnd

getVal:
    push ebp
    mov ebp, esp        ;stack frame

    push ebx
    push ecx

    mov eax, 10          ;operacion de getVal
    mov ebx, [ebp+8]    ;ebx = Variable Name
    mov ecx, [ebp+12]   ;ecx = buffer

    int 80h

    pop ecx
    pop ebx

    leave               ;restaura el stack
    ret

read:
    push ebp
    mov ebp, esp        ;stack frame

    push ebx
    push ecx
    push edx            ;backup registros

    mov eax, 1          ;operacion de read
    mov ebx, [ebp+8]    ;ebx = file descriptor
    mov ecx, [ebp+12]   ;ecx = buffer
    mov edx, [ebp+16]   ;edx = size

    int 80h

    pop edx
    pop ecx
    pop ebx

    leave               ;restaura el stack
    ret

setVal:
    push ebp
    mov ebp, esp    ; stack frame

    push ebx
    push ecx

    mov eax, 11
    mov ebx, [ebp+8]    ; operacion de setVal
    mov ecx, [ebp+12]   ; buffer

    int 80h

    pop ecx
    pop ebx

    leave               ; stack original restaurado
    ret

write:
    push ebp
    mov ebp, esp    ; stack frame

    push ebx
    push ecx
    push edx        ;backup registros

    mov eax, 0
    mov ebx, [ebp+8]    ; file descriptor
    mov ecx, [ebp+12]   ; buffer
    mov edx, [ebp+16]   ; size

    int 80h

    pop edx
    pop ecx
    pop ebx

    leave               ; stack original restaurado
    ret

ioIn:
    push ebp
    mov ebp, esp
    push ebx
    push ecx             ; backup

    mov eax, 2           ; int_80_handler = in operation
    mov ecx, [ebp+8]     ; ecx = destino de la lectura del puerto
    mov ebx, [ebp+12]    ; ebx = puerto del que se debe leer

    int 80h

    pop ecx
    pop ebx
    leave               ; stack original restaurado
    ret

ioOut:
    push ebp
    mov ebp, esp
    push ebx
    push ecx             ; backup

    mov eax, 3
    mov ecx, [ebp+8]     ; ecx = dato a escribir
    mov ebx, [ebp+12]    ; ebx = puerto al que se debe escribir

    int 80h

    pop ecx
    pop ebx
    leave               ; stack original restaurado
    ret

restart:
    ;Wait for a empty Input Buffer
    wait1:
    in   al, 0x064
    test al, 00000010b
    jne  wait1

    ;Send 0xD1 to the KBC. This is the command to write the Outputport.
    mov  al, 0xD1
    out  0x64, al

    ;Wait for a empty Input Buffer
    wait2:
    in   al, 0x064
    test al, 00000010b
    jne  wait2

    ;Now we can write the new value (0xFE) for the Outputport to port 0x60
    mov  al, 0xFE
    out  0x60, al

    ret



; Debug para el BOCHS, detiene la ejecució;
; Para continuar colocar en el BOCHSDBG: set $eax=0


_debug:
    push ebp
    mov  ebp, esp
    push eax
vuelve:
    mov eax, 1
    cmp eax, 0
    jne vuelve
    pop eax
    pop ebp
    retn

